"use strict";

var GuessContent = function(text) {
    if (text) {
        var obj = JSON.parse(text);
        this.publisher = obj.publisher;
        this.pubHalfData = obj.pubHalfData;
        this.pubGuessResult = obj.pubGuessResult;

        this.acceptor = obj.acceptor;
        this.accHalfData = obj.accHalfData;
        this.accGuessResult = obj.accGuessResult;
        
        this.guessType = obj.guessType;
        this.guessNasPrice = new BigNumber(obj.guessNasPrice);
        this.isDone = obj.isDone;
    } else {
        this.publisher = "";
        this.pubHalfData = [];
        this.pubGuessResult = "";

        this.acceptor = "";
        this.accHalfData = [];
        this.accGuessResult = "";

        this.guessType = "";
        this.guessNasPrice = 0;
        this.isDone = true;
    }
};

GuessContent.prototype = {
    toString: function () {
        return JSON.stringify(this);
    }
};

var GuessContract = function () {
    LocalContractStorage.defineMapProperty(this, "guessContent", {
        parse: function(text) {
            return new GuessContent(text);
        },
        stringify: function(o) {
            return o.toString();
        }
    });

    LocalContractStorage.defineMapProperty(this, "challengeIndex");
    LocalContractStorage.defineProperty(this, "challengesCount");
};

function isPrimeNum(n) {
    for (var i = 2; i < num; i++) {
        if (num % i == 0) {
            return false;
        }
    };
    return true;
};

GuessContract.prototype = {
    init: function() {
        this.challengesCount = 0;
    },
    publish: function (pubGuessResult, guessType) {
        if(pubGuessResult === "" || guessType === "") {
            throw new Error("empty params in  pubGuessResult / guessType");
        }
        if (guessType != "GEC" && guessType != "GPC" && guessType != "GEM") {
            //GEC: Guess Even Counts , who is nearest to the fact
            //GPC: Guess Prime Counts , who is nearest to the fact
            //GEM: Guess Even is More , 50 % rate to win the game
            throw new Error("guessType is not allowed");
        }

        var from = Blockchain.transaction.from;
        var value = Blockchain.transaction.value;

        if (new BigNumber(value) == 0 || new BigNumber(value) > 5000000000000000000) {
            throw new Error("your challenge NAS is not allowed: nas = " + value);
        }

        var content = this.guessContent.get(from + guessType);
        if (content && !content.isDone) {
            throw new Error("sorry you have published such a challenge...");
        }

        //generate random data
        var arr = [];
        for (var i = 0; i < 50; i ++) {
            var rand = parseInt(Math.random() * 1000);
            arr[i] = rand;
        }

        content = new GuessContent();
        content.publisher = from;
        content.pubHalfData = arr;
        content.pubGuessResult = pubGuessResult;
        content.guessNasPrice = new BigNumber(value);
        content.isDone = false;

        this.challengeIndex.put(this.challengesCount, from + guessType);
        this.guessContent.put(from + guessType, content);
        this.challengesCount ++;
    },

    accept: function (accGuessResult, guessType, from) {
        if (accGuessResult === "" || guessType === "" || from === "") {
            throw new Error("empty accGuessResult / guessType / from");
        }

        var acceptor = Blockchain.transaction.from;
        var value = Blockchain.transaction.value;

        var content = this.guessContent.get(from + guessType);
        if (!content) {
            throw new Error("the challenge not founded...");
        }
        if (content.isDone) {
            throw new Error("the challenge was finished ...");
        }
        if (content.guessNasPrice != new BigNumber(value)) {
            throw new Error("the challenge NAS input is not allowed, guessNasPrice = " + content.guessNasPrice + ", value = " + value);
        } 
        if (acceptor == content.publisher) {
            throw new Error("you can not challenge yourself");
        }

        //生成另一半随机数
        var arr = [];
        for (var i = 0; i < 50; i++) {
            var rand = parseInt(Math.random() * 1000);
            arr[i] = rand;
        }

        var count = 0;
        var subPublisher = 0;
        var subAcceptor = 0;
        var winner = 0;
        //判断谁输谁赢的时候
        if (content.pubGuessResult == accGuessResult) {
            //两人没有输赢之分,押金退还,但是两人输了手续费,所以会尽量不选一样多
            winner = 0;
        } else if (guessType == "GPC") { //猜素数的个数,谁更接近谁赢
            for (var i = 0; i < arr.length; i++) {
                if (isPrimeNum(arr[i])) {
                    count ++;
                }
            }
            var arrPub = content.pubHalfData;
            for (var i = 0; i < arrPub.length; i ++) {
                if (isPrimeNum(arrPub[i])) {
                    count ++;
                }
            }

            subPublisher = Math.abs(count - new BigNumber(content.pubGuessResult));
            subAcceptor = Math.abs(count - new BigNumber(accGuessResult));
            winner = subPublisher < subAcceptor ? 1 : 2;
        } else {
            //猜偶数的个数或者偶数多还是奇数多
            for (var i = 0; i < arr.length; i++) {
                if (arr[i] % 2 == 0) {
                    count ++;
                }
            }
            var arrPub = content.pubHalfData;
            for (var i = 0; i < arrPub.length; i ++) {
                if (arrPub[i] % 2 == 0) {
                    count ++;
                }
            }

            if(guessType == "GEC") { //猜偶数的个数,谁更接近谁赢
                subPublisher = Math.abs(count - new BigNumber(content.pubGuessResult));
                subAcceptor = Math.abs(count - new BigNumber(accGuessResult));
                winner = subPublisher < subAcceptor ? 1 : 2;
            }  else if (guessType == "GEM") { //猜测偶数的个数更多
                if (count == 50) {
                    winner = 0;
                } else if(count > 50) {
                    winner = content.pubGuessResult == "em" ? 1 : 2; 
                } else if (count < 50) {            
                    winner = content.pubGuessResult == "el" ? 1 : 2;
                }
            }
        }

        if (winner == 0) {
            var result = Blockchain.transfer(acceptor, new BigNumber(value));
            if (!result) {
                throw new Error("transfer failed.");
            }
            result = Blockchain.transfer(content.publisher, content.guessNasPrice * 2);
            if (!result) {
                throw new Error("transfer failed.");
            }
        } else if (winner == 1) {
            result = Blockchain.transfer(content.publisher, content.guessNasPrice * 2);
            if (!result) {
                throw new Error("transfer failed.");
            }
        } else if (winner == 2) {
            var result = Blockchain.transfer(acceptor, content.guessNasPrice);
            if (!result) {
                throw new Error("transfer failed.");
            }
        }

        //将这次挑战永久记录在BlockChain中,不可抵赖不可篡改
        content.acceptor = acceptor;
        content.accGuessResult = accGuessResult;
        content.accHalfData = arr;

        content.isDone = true;

        this.guessContent.put(from + guessType, content);
    },

    fetchHalfData: function (guessType) {
        if (guessType === "") {
            throw new Error("empty guessType");
        }

        var from = Blockchain.transaction.from;
        var content = this.guessContent.get(from + guessType);
        if(!content) {
            throw new Error("the challenge not founded...");
        }

        return content;
    },

    getTotalPages: function(pageSize) {
        var challengesCount = this.challengesCount;
        var totalPages = challengesCount / pageSize + 1;
        return totalPages;
    },

    fetchByPage: function (page, pageSize) {
        if (page < 1 || pageSize < 0) {
            throw new Error("page / pageSize not allowed")
        }

        var challengesCount = this.challengesCount;
        var challengeIndex = this.challengeIndex;
        var totalPages = challengesCount / pageSize + 1;
        if (page > totalPages) {
            throw new Error("no more pages");
        }

        var result = [];
        var tempSize = pageSize;
        var i = (page - 1) * pageSize;
        if (page == totalPages) {
            //if it is the last page, the size should be :
            tempSize = challengesCount - i;
        }
        for (; i < tempSize; i ++) {
            var ci = challengeIndex.get(i);
            if (ci != null && ci !== "") {
                var obj = this.guessContent.get(ci);
                var temp = {
                    index: i,
                    challengeI: ci,
                    guessContent: obj
                };
    
                result.push(temp);
            }
        }

        return result;
        //return JSON.parse(JSON.stringify(result));
    }
};

module.exports = GuessContract;